home *** CD-ROM | disk | FTP | other *** search
/ Introduction to 3D Game …ogramming with DirectX 12 / Introduction-to-3D-Game-Programming-with-DirectX-12.ISO / Code.Textures / Chapter 12 The Geometry Shader / TreeBillboards / TreeBillboardsApp.cpp < prev    next >
C/C++ Source or Header  |  2016-03-02  |  45KB  |  1,243 lines

  1. //***************************************************************************************
  2. // TreeBillboardsApp.cpp by Frank Luna (C) 2015 All Rights Reserved.
  3. //***************************************************************************************
  4.  
  5. #include "../../Common/d3dApp.h"
  6. #include "../../Common/MathHelper.h"
  7. #include "../../Common/UploadBuffer.h"
  8. #include "../../Common/GeometryGenerator.h"
  9. #include "FrameResource.h"
  10. #include "Waves.h"
  11.  
  12. using Microsoft::WRL::ComPtr;
  13. using namespace DirectX;
  14. using namespace DirectX::PackedVector;
  15.  
  16. #pragma comment(lib, "d3dcompiler.lib")
  17. #pragma comment(lib, "D3D12.lib")
  18.  
  19. const int gNumFrameResources = 3;
  20.  
  21. // Lightweight structure stores parameters to draw a shape.  This will
  22. // vary from app-to-app.
  23. struct RenderItem
  24. {
  25.     RenderItem() = default;
  26.  
  27.     // World matrix of the shape that describes the object's local space
  28.     // relative to the world space, which defines the position, orientation,
  29.     // and scale of the object in the world.
  30.     XMFLOAT4X4 World = MathHelper::Identity4x4();
  31.  
  32.     XMFLOAT4X4 TexTransform = MathHelper::Identity4x4();
  33.  
  34.     // Dirty flag indicating the object data has changed and we need to update the constant buffer.
  35.     // Because we have an object cbuffer for each FrameResource, we have to apply the
  36.     // update to each FrameResource.  Thus, when we modify obect data we should set 
  37.     // NumFramesDirty = gNumFrameResources so that each frame resource gets the update.
  38.     int NumFramesDirty = gNumFrameResources;
  39.  
  40.     // Index into GPU constant buffer corresponding to the ObjectCB for this render item.
  41.     UINT ObjCBIndex = -1;
  42.  
  43.     Material* Mat = nullptr;
  44.     MeshGeometry* Geo = nullptr;
  45.  
  46.     // Primitive topology.
  47.     D3D12_PRIMITIVE_TOPOLOGY PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  48.  
  49.     // DrawIndexedInstanced parameters.
  50.     UINT IndexCount = 0;
  51.     UINT StartIndexLocation = 0;
  52.     int BaseVertexLocation = 0;
  53. };
  54.  
  55. enum class RenderLayer : int
  56. {
  57.     Opaque = 0,
  58.     Transparent,
  59.     AlphaTested,
  60.     AlphaTestedTreeSprites,
  61.     Count
  62. };
  63.  
  64. class TreeBillboardsApp : public D3DApp
  65. {
  66. public:
  67.     TreeBillboardsApp(HINSTANCE hInstance);
  68.     TreeBillboardsApp(const TreeBillboardsApp& rhs) = delete;
  69.     TreeBillboardsApp& operator=(const TreeBillboardsApp& rhs) = delete;
  70.     ~TreeBillboardsApp();
  71.  
  72.     virtual bool Initialize()override;
  73.  
  74. private:
  75.     virtual void OnResize()override;
  76.     virtual void Update(const GameTimer& gt)override;
  77.     virtual void Draw(const GameTimer& gt)override;
  78.  
  79.     virtual void OnMouseDown(WPARAM btnState, int x, int y)override;
  80.     virtual void OnMouseUp(WPARAM btnState, int x, int y)override;
  81.     virtual void OnMouseMove(WPARAM btnState, int x, int y)override;
  82.  
  83.     void OnKeyboardInput(const GameTimer& gt);
  84.     void UpdateCamera(const GameTimer& gt);
  85.     void AnimateMaterials(const GameTimer& gt);
  86.     void UpdateObjectCBs(const GameTimer& gt);
  87.     void UpdateMaterialCBs(const GameTimer& gt);
  88.     void UpdateMainPassCB(const GameTimer& gt);
  89.     void UpdateWaves(const GameTimer& gt); 
  90.  
  91.     void LoadTextures();
  92.     void BuildRootSignature();
  93.     void BuildDescriptorHeaps();
  94.     void BuildShadersAndInputLayouts();
  95.     void BuildLandGeometry();
  96.     void BuildWavesGeometry();
  97.     void BuildBoxGeometry();
  98.     void BuildTreeSpritesGeometry();
  99.     void BuildPSOs();
  100.     void BuildFrameResources();
  101.     void BuildMaterials();
  102.     void BuildRenderItems();
  103.     void DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems);
  104.  
  105.     std::array<const CD3DX12_STATIC_SAMPLER_DESC, 6> GetStaticSamplers();
  106.  
  107.     float GetHillsHeight(float x, float z)const;
  108.     XMFLOAT3 GetHillsNormal(float x, float z)const;
  109.  
  110. private:
  111.  
  112.     std::vector<std::unique_ptr<FrameResource>> mFrameResources;
  113.     FrameResource* mCurrFrameResource = nullptr;
  114.     int mCurrFrameResourceIndex = 0;
  115.  
  116.     UINT mCbvSrvDescriptorSize = 0;
  117.  
  118.     ComPtr<ID3D12RootSignature> mRootSignature = nullptr;
  119.  
  120.     ComPtr<ID3D12DescriptorHeap> mSrvDescriptorHeap = nullptr;
  121.  
  122.     std::unordered_map<std::string, std::unique_ptr<MeshGeometry>> mGeometries;
  123.     std::unordered_map<std::string, std::unique_ptr<Material>> mMaterials;
  124.     std::unordered_map<std::string, std::unique_ptr<Texture>> mTextures;
  125.     std::unordered_map<std::string, ComPtr<ID3DBlob>> mShaders;
  126.     std::unordered_map<std::string, ComPtr<ID3D12PipelineState>> mPSOs;
  127.  
  128.     std::vector<D3D12_INPUT_ELEMENT_DESC> mStdInputLayout;
  129.     std::vector<D3D12_INPUT_ELEMENT_DESC> mTreeSpriteInputLayout;
  130.  
  131.     RenderItem* mWavesRitem = nullptr;
  132.  
  133.     // List of all the render items.
  134.     std::vector<std::unique_ptr<RenderItem>> mAllRitems;
  135.  
  136.     // Render items divided by PSO.
  137.     std::vector<RenderItem*> mRitemLayer[(int)RenderLayer::Count];
  138.  
  139.     std::unique_ptr<Waves> mWaves;
  140.  
  141.     PassConstants mMainPassCB;
  142.  
  143.     XMFLOAT3 mEyePos = { 0.0f, 0.0f, 0.0f };
  144.     XMFLOAT4X4 mView = MathHelper::Identity4x4();
  145.     XMFLOAT4X4 mProj = MathHelper::Identity4x4();
  146.  
  147.     float mTheta = 1.5f*XM_PI;
  148.     float mPhi = XM_PIDIV2 - 0.1f;
  149.     float mRadius = 50.0f;
  150.  
  151.     POINT mLastMousePos;
  152. };
  153.  
  154. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
  155.     PSTR cmdLine, int showCmd)
  156. {
  157.     // Enable run-time memory check for debug builds.
  158. #if defined(DEBUG) | defined(_DEBUG)
  159.     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
  160. #endif
  161.  
  162.     try
  163.     {
  164.         TreeBillboardsApp theApp(hInstance);
  165.         if(!theApp.Initialize())
  166.             return 0;
  167.  
  168.         return theApp.Run();
  169.     }
  170.     catch(DxException& e)
  171.     {
  172.         MessageBox(nullptr, e.ToString().c_str(), L"HR Failed", MB_OK);
  173.         return 0;
  174.     }
  175. }
  176.  
  177. TreeBillboardsApp::TreeBillboardsApp(HINSTANCE hInstance)
  178.     : D3DApp(hInstance)
  179. {
  180. }
  181.  
  182. TreeBillboardsApp::~TreeBillboardsApp()
  183. {
  184.     if(md3dDevice != nullptr)
  185.         FlushCommandQueue();
  186. }
  187.  
  188. bool TreeBillboardsApp::Initialize()
  189. {
  190.     if(!D3DApp::Initialize())
  191.         return false;
  192.  
  193.     // Reset the command list to prep for initialization commands.
  194.     ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), nullptr));
  195.  
  196.     // Get the increment size of a descriptor in this heap type.  This is hardware specific, 
  197.     // so we have to query this information.
  198.     mCbvSrvDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
  199.  
  200.     mWaves = std::make_unique<Waves>(128, 128, 1.0f, 0.03f, 4.0f, 0.2f);
  201.  
  202.     LoadTextures();
  203.     BuildRootSignature();
  204.     BuildDescriptorHeaps();
  205.     BuildShadersAndInputLayouts();
  206.     BuildLandGeometry();
  207.     BuildWavesGeometry();
  208.     BuildBoxGeometry();
  209.     BuildTreeSpritesGeometry();
  210.     BuildMaterials();
  211.     BuildRenderItems();
  212.     BuildFrameResources();
  213.     BuildPSOs();
  214.  
  215.     // Execute the initialization commands.
  216.     ThrowIfFailed(mCommandList->Close());
  217.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  218.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  219.  
  220.     // Wait until initialization is complete.
  221.     FlushCommandQueue();
  222.  
  223.     return true;
  224. }
  225.  
  226. void TreeBillboardsApp::OnResize()
  227. {
  228.     D3DApp::OnResize();
  229.  
  230.     // The window resized, so update the aspect ratio and recompute the projection matrix.
  231.     XMMATRIX P = XMMatrixPerspectiveFovLH(0.25f*MathHelper::Pi, AspectRatio(), 1.0f, 1000.0f);
  232.     XMStoreFloat4x4(&mProj, P);
  233. }
  234.  
  235. void TreeBillboardsApp::Update(const GameTimer& gt)
  236. {
  237.     OnKeyboardInput(gt);
  238.     UpdateCamera(gt);
  239.  
  240.     // Cycle through the circular frame resource array.
  241.     mCurrFrameResourceIndex = (mCurrFrameResourceIndex + 1) % gNumFrameResources;
  242.     mCurrFrameResource = mFrameResources[mCurrFrameResourceIndex].get();
  243.  
  244.     // Has the GPU finished processing the commands of the current frame resource?
  245.     // If not, wait until the GPU has completed commands up to this fence point.
  246.     if(mCurrFrameResource->Fence != 0 && mFence->GetCompletedValue() < mCurrFrameResource->Fence)
  247.     {
  248.         HANDLE eventHandle = CreateEventEx(nullptr, false, false, EVENT_ALL_ACCESS);
  249.         ThrowIfFailed(mFence->SetEventOnCompletion(mCurrFrameResource->Fence, eventHandle));
  250.         WaitForSingleObject(eventHandle, INFINITE);
  251.         CloseHandle(eventHandle);
  252.     }
  253.  
  254.     AnimateMaterials(gt);
  255.     UpdateObjectCBs(gt);
  256.     UpdateMaterialCBs(gt);
  257.     UpdateMainPassCB(gt);
  258.     UpdateWaves(gt);
  259. }
  260.  
  261. void TreeBillboardsApp::Draw(const GameTimer& gt)
  262. {
  263.     auto cmdListAlloc = mCurrFrameResource->CmdListAlloc;
  264.  
  265.     // Reuse the memory associated with command recording.
  266.     // We can only reset when the associated command lists have finished execution on the GPU.
  267.     ThrowIfFailed(cmdListAlloc->Reset());
  268.  
  269.     // A command list can be reset after it has been added to the command queue via ExecuteCommandList.
  270.     // Reusing the command list reuses memory.
  271.     ThrowIfFailed(mCommandList->Reset(cmdListAlloc.Get(), mPSOs["opaque"].Get()));
  272.  
  273.     mCommandList->RSSetViewports(1, &mScreenViewport);
  274.     mCommandList->RSSetScissorRects(1, &mScissorRect);
  275.  
  276.     // Indicate a state transition on the resource usage.
  277.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  278.         D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
  279.  
  280.     // Clear the back buffer and depth buffer.
  281.     mCommandList->ClearRenderTargetView(CurrentBackBufferView(), (float*)&mMainPassCB.FogColor, 0, nullptr);
  282.     mCommandList->ClearDepthStencilView(DepthStencilView(), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
  283.  
  284.     // Specify the buffers we are going to render to.
  285.     mCommandList->OMSetRenderTargets(1, &CurrentBackBufferView(), true, &DepthStencilView());
  286.  
  287.     ID3D12DescriptorHeap* descriptorHeaps[] = { mSrvDescriptorHeap.Get() };
  288.     mCommandList->SetDescriptorHeaps(_countof(descriptorHeaps), descriptorHeaps);
  289.  
  290.     mCommandList->SetGraphicsRootSignature(mRootSignature.Get());
  291.  
  292.     auto passCB = mCurrFrameResource->PassCB->Resource();
  293.     mCommandList->SetGraphicsRootConstantBufferView(2, passCB->GetGPUVirtualAddress());
  294.  
  295.     DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Opaque]);
  296.  
  297.     mCommandList->SetPipelineState(mPSOs["alphaTested"].Get());
  298.     DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::AlphaTested]);
  299.  
  300.     mCommandList->SetPipelineState(mPSOs["treeSprites"].Get());
  301.     DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::AlphaTestedTreeSprites]);
  302.  
  303.     mCommandList->SetPipelineState(mPSOs["transparent"].Get());
  304.     DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Transparent]);
  305.  
  306.     // Indicate a state transition on the resource usage.
  307.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  308.         D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
  309.  
  310.     // Done recording commands.
  311.     ThrowIfFailed(mCommandList->Close());
  312.  
  313.     // Add the command list to the queue for execution.
  314.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  315.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  316.  
  317.     // Swap the back and front buffers
  318.     ThrowIfFailed(mSwapChain->Present(0, 0));
  319.     mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;
  320.  
  321.     // Advance the fence value to mark commands up to this fence point.
  322.     mCurrFrameResource->Fence = ++mCurrentFence;
  323.  
  324.     // Add an instruction to the command queue to set a new fence point. 
  325.     // Because we are on the GPU timeline, the new fence point won't be 
  326.     // set until the GPU finishes processing all the commands prior to this Signal().
  327.     mCommandQueue->Signal(mFence.Get(), mCurrentFence);
  328. }
  329.  
  330. void TreeBillboardsApp::OnMouseDown(WPARAM btnState, int x, int y)
  331. {
  332.     mLastMousePos.x = x;
  333.     mLastMousePos.y = y;
  334.  
  335.     SetCapture(mhMainWnd);
  336. }
  337.  
  338. void TreeBillboardsApp::OnMouseUp(WPARAM btnState, int x, int y)
  339. {
  340.     ReleaseCapture();
  341. }
  342.  
  343. void TreeBillboardsApp::OnMouseMove(WPARAM btnState, int x, int y)
  344. {
  345.     if((btnState & MK_LBUTTON) != 0)
  346.     {
  347.         // Make each pixel correspond to a quarter of a degree.
  348.         float dx = XMConvertToRadians(0.25f*static_cast<float>(x - mLastMousePos.x));
  349.         float dy = XMConvertToRadians(0.25f*static_cast<float>(y - mLastMousePos.y));
  350.  
  351.         // Update angles based on input to orbit camera around box.
  352.         mTheta += dx;
  353.         mPhi += dy;
  354.  
  355.         // Restrict the angle mPhi.
  356.         mPhi = MathHelper::Clamp(mPhi, 0.1f, MathHelper::Pi - 0.1f);
  357.     }
  358.     else if((btnState & MK_RBUTTON) != 0)
  359.     {
  360.         // Make each pixel correspond to 0.2 unit in the scene.
  361.         float dx = 0.2f*static_cast<float>(x - mLastMousePos.x);
  362.         float dy = 0.2f*static_cast<float>(y - mLastMousePos.y);
  363.  
  364.         // Update the camera radius based on input.
  365.         mRadius += dx - dy;
  366.  
  367.         // Restrict the radius.
  368.         mRadius = MathHelper::Clamp(mRadius, 5.0f, 150.0f);
  369.     }
  370.  
  371.     mLastMousePos.x = x;
  372.     mLastMousePos.y = y;
  373. }
  374.  
  375. void TreeBillboardsApp::OnKeyboardInput(const GameTimer& gt)
  376. {
  377. }
  378.  
  379. void TreeBillboardsApp::UpdateCamera(const GameTimer& gt)
  380. {
  381.     // Convert Spherical to Cartesian coordinates.
  382.     mEyePos.x = mRadius*sinf(mPhi)*cosf(mTheta);
  383.     mEyePos.z = mRadius*sinf(mPhi)*sinf(mTheta);
  384.     mEyePos.y = mRadius*cosf(mPhi);
  385.  
  386.     // Build the view matrix.
  387.     XMVECTOR pos = XMVectorSet(mEyePos.x, mEyePos.y, mEyePos.z, 1.0f);
  388.     XMVECTOR target = XMVectorZero();
  389.     XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
  390.  
  391.     XMMATRIX view = XMMatrixLookAtLH(pos, target, up);
  392.     XMStoreFloat4x4(&mView, view);
  393. }
  394.  
  395. void TreeBillboardsApp::AnimateMaterials(const GameTimer& gt)
  396. {
  397.     // Scroll the water material texture coordinates.
  398.     auto waterMat = mMaterials["water"].get();
  399.  
  400.     float& tu = waterMat->MatTransform(3, 0);
  401.     float& tv = waterMat->MatTransform(3, 1);
  402.  
  403.     tu += 0.1f * gt.DeltaTime();
  404.     tv += 0.02f * gt.DeltaTime();
  405.  
  406.     if(tu >= 1.0f)
  407.         tu -= 1.0f;
  408.  
  409.     if(tv >= 1.0f)
  410.         tv -= 1.0f;
  411.  
  412.     waterMat->MatTransform(3, 0) = tu;
  413.     waterMat->MatTransform(3, 1) = tv;
  414.  
  415.     // Material has changed, so need to update cbuffer.
  416.     waterMat->NumFramesDirty = gNumFrameResources;
  417. }
  418.  
  419. void TreeBillboardsApp::UpdateObjectCBs(const GameTimer& gt)
  420. {
  421.     auto currObjectCB = mCurrFrameResource->ObjectCB.get();
  422.     for(auto& e : mAllRitems)
  423.     {
  424.         // Only update the cbuffer data if the constants have changed.  
  425.         // This needs to be tracked per frame resource.
  426.         if(e->NumFramesDirty > 0)
  427.         {
  428.             XMMATRIX world = XMLoadFloat4x4(&e->World);
  429.             XMMATRIX texTransform = XMLoadFloat4x4(&e->TexTransform);
  430.  
  431.             ObjectConstants objConstants;
  432.             XMStoreFloat4x4(&objConstants.World, XMMatrixTranspose(world));
  433.             XMStoreFloat4x4(&objConstants.TexTransform, XMMatrixTranspose(texTransform));
  434.  
  435.             currObjectCB->CopyData(e->ObjCBIndex, objConstants);
  436.  
  437.             // Next FrameResource need to be updated too.
  438.             e->NumFramesDirty--;
  439.         }
  440.     }
  441. }
  442.  
  443. void TreeBillboardsApp::UpdateMaterialCBs(const GameTimer& gt)
  444. {
  445.     auto currMaterialCB = mCurrFrameResource->MaterialCB.get();
  446.     for(auto& e : mMaterials)
  447.     {
  448.         // Only update the cbuffer data if the constants have changed.  If the cbuffer
  449.         // data changes, it needs to be updated for each FrameResource.
  450.         Material* mat = e.second.get();
  451.         if(mat->NumFramesDirty > 0)
  452.         {
  453.             XMMATRIX matTransform = XMLoadFloat4x4(&mat->MatTransform);
  454.  
  455.             MaterialConstants matConstants;
  456.             matConstants.DiffuseAlbedo = mat->DiffuseAlbedo;
  457.             matConstants.FresnelR0 = mat->FresnelR0;
  458.             matConstants.Roughness = mat->Roughness;
  459.             XMStoreFloat4x4(&matConstants.MatTransform, XMMatrixTranspose(matTransform));
  460.  
  461.             currMaterialCB->CopyData(mat->MatCBIndex, matConstants);
  462.  
  463.             // Next FrameResource need to be updated too.
  464.             mat->NumFramesDirty--;
  465.         }
  466.     }
  467. }
  468.  
  469. void TreeBillboardsApp::UpdateMainPassCB(const GameTimer& gt)
  470. {
  471.     XMMATRIX view = XMLoadFloat4x4(&mView);
  472.     XMMATRIX proj = XMLoadFloat4x4(&mProj);
  473.  
  474.     XMMATRIX viewProj = XMMatrixMultiply(view, proj);
  475.     XMMATRIX invView = XMMatrixInverse(&XMMatrixDeterminant(view), view);
  476.     XMMATRIX invProj = XMMatrixInverse(&XMMatrixDeterminant(proj), proj);
  477.     XMMATRIX invViewProj = XMMatrixInverse(&XMMatrixDeterminant(viewProj), viewProj);
  478.  
  479.     XMStoreFloat4x4(&mMainPassCB.View, XMMatrixTranspose(view));
  480.     XMStoreFloat4x4(&mMainPassCB.InvView, XMMatrixTranspose(invView));
  481.     XMStoreFloat4x4(&mMainPassCB.Proj, XMMatrixTranspose(proj));
  482.     XMStoreFloat4x4(&mMainPassCB.InvProj, XMMatrixTranspose(invProj));
  483.     XMStoreFloat4x4(&mMainPassCB.ViewProj, XMMatrixTranspose(viewProj));
  484.     XMStoreFloat4x4(&mMainPassCB.InvViewProj, XMMatrixTranspose(invViewProj));
  485.     mMainPassCB.EyePosW = mEyePos;
  486.     mMainPassCB.RenderTargetSize = XMFLOAT2((float)mClientWidth, (float)mClientHeight);
  487.     mMainPassCB.InvRenderTargetSize = XMFLOAT2(1.0f / mClientWidth, 1.0f / mClientHeight);
  488.     mMainPassCB.NearZ = 1.0f;
  489.     mMainPassCB.FarZ = 1000.0f;
  490.     mMainPassCB.TotalTime = gt.TotalTime();
  491.     mMainPassCB.DeltaTime = gt.DeltaTime();
  492.     mMainPassCB.AmbientLight = { 0.25f, 0.25f, 0.35f, 1.0f };
  493.     mMainPassCB.Lights[0].Direction = { 0.57735f, -0.57735f, 0.57735f };
  494.     mMainPassCB.Lights[0].Strength = { 0.6f, 0.6f, 0.6f };
  495.     mMainPassCB.Lights[1].Direction = { -0.57735f, -0.57735f, 0.57735f };
  496.     mMainPassCB.Lights[1].Strength = { 0.3f, 0.3f, 0.3f };
  497.     mMainPassCB.Lights[2].Direction = { 0.0f, -0.707f, -0.707f };
  498.     mMainPassCB.Lights[2].Strength = { 0.15f, 0.15f, 0.15f };
  499.  
  500.     auto currPassCB = mCurrFrameResource->PassCB.get();
  501.     currPassCB->CopyData(0, mMainPassCB);
  502. }
  503.  
  504. void TreeBillboardsApp::UpdateWaves(const GameTimer& gt)
  505. {
  506.     // Every quarter second, generate a random wave.
  507.     static float t_base = 0.0f;
  508.     if((mTimer.TotalTime() - t_base) >= 0.25f)
  509.     {
  510.         t_base += 0.25f;
  511.  
  512.         int i = MathHelper::Rand(4, mWaves->RowCount() - 5);
  513.         int j = MathHelper::Rand(4, mWaves->ColumnCount() - 5);
  514.  
  515.         float r = MathHelper::RandF(0.2f, 0.5f);
  516.  
  517.         mWaves->Disturb(i, j, r);
  518.     }
  519.  
  520.     // Update the wave simulation.
  521.     mWaves->Update(gt.DeltaTime());
  522.  
  523.     // Update the wave vertex buffer with the new solution.
  524.     auto currWavesVB = mCurrFrameResource->WavesVB.get();
  525.     for(int i = 0; i < mWaves->VertexCount(); ++i)
  526.     {
  527.         Vertex v;
  528.  
  529.         v.Pos = mWaves->Position(i);
  530.         v.Normal = mWaves->Normal(i);
  531.         
  532.         // Derive tex-coords from position by 
  533.         // mapping [-w/2,w/2] --> [0,1]
  534.         v.TexC.x = 0.5f + v.Pos.x / mWaves->Width();
  535.         v.TexC.y = 0.5f - v.Pos.z / mWaves->Depth();
  536.  
  537.         currWavesVB->CopyData(i, v);
  538.     }
  539.  
  540.     // Set the dynamic VB of the wave renderitem to the current frame VB.
  541.     mWavesRitem->Geo->VertexBufferGPU = currWavesVB->Resource();
  542. }
  543.  
  544. void TreeBillboardsApp::LoadTextures()
  545. {
  546.     auto grassTex = std::make_unique<Texture>();
  547.     grassTex->Name = "grassTex";
  548.     grassTex->Filename = L"../../Textures/grass.dds";
  549.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  550.         mCommandList.Get(), grassTex->Filename.c_str(),
  551.         grassTex->Resource, grassTex->UploadHeap));
  552.  
  553.     auto waterTex = std::make_unique<Texture>();
  554.     waterTex->Name = "waterTex";
  555.     waterTex->Filename = L"../../Textures/water1.dds";
  556.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  557.         mCommandList.Get(), waterTex->Filename.c_str(),
  558.         waterTex->Resource, waterTex->UploadHeap));
  559.  
  560.     auto fenceTex = std::make_unique<Texture>();
  561.     fenceTex->Name = "fenceTex";
  562.     fenceTex->Filename = L"../../Textures/WireFence.dds";
  563.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  564.         mCommandList.Get(), fenceTex->Filename.c_str(),
  565.         fenceTex->Resource, fenceTex->UploadHeap));
  566.  
  567.     auto treeArrayTex = std::make_unique<Texture>();
  568.     treeArrayTex->Name = "treeArrayTex";
  569.     treeArrayTex->Filename = L"../../Textures/treeArray2.dds";
  570.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  571.         mCommandList.Get(), treeArrayTex->Filename.c_str(),
  572.         treeArrayTex->Resource, treeArrayTex->UploadHeap));
  573.  
  574.     mTextures[grassTex->Name] = std::move(grassTex);
  575.     mTextures[waterTex->Name] = std::move(waterTex);
  576.     mTextures[fenceTex->Name] = std::move(fenceTex);
  577.     mTextures[treeArrayTex->Name] = std::move(treeArrayTex);
  578. }
  579.  
  580. void TreeBillboardsApp::BuildRootSignature()
  581. {
  582.     CD3DX12_DESCRIPTOR_RANGE texTable;
  583.     texTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);
  584.  
  585.     // Root parameter can be a table, root descriptor or root constants.
  586.     CD3DX12_ROOT_PARAMETER slotRootParameter[4];
  587.  
  588.     // Perfomance TIP: Order from most frequent to least frequent.
  589.     slotRootParameter[0].InitAsDescriptorTable(1, &texTable, D3D12_SHADER_VISIBILITY_PIXEL);
  590.     slotRootParameter[1].InitAsConstantBufferView(0);
  591.     slotRootParameter[2].InitAsConstantBufferView(1);
  592.     slotRootParameter[3].InitAsConstantBufferView(2);
  593.  
  594.     auto staticSamplers = GetStaticSamplers();
  595.  
  596.     // A root signature is an array of root parameters.
  597.     CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(4, slotRootParameter,
  598.         (UINT)staticSamplers.size(), staticSamplers.data(),
  599.         D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
  600.  
  601.     // create a root signature with a single slot which points to a descriptor range consisting of a single constant buffer
  602.     ComPtr<ID3DBlob> serializedRootSig = nullptr;
  603.     ComPtr<ID3DBlob> errorBlob = nullptr;
  604.     HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
  605.         serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());
  606.  
  607.     if(errorBlob != nullptr)
  608.     {
  609.         ::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
  610.     }
  611.     ThrowIfFailed(hr);
  612.  
  613.     ThrowIfFailed(md3dDevice->CreateRootSignature(
  614.         0,
  615.         serializedRootSig->GetBufferPointer(),
  616.         serializedRootSig->GetBufferSize(),
  617.         IID_PPV_ARGS(mRootSignature.GetAddressOf())));
  618. }
  619.  
  620. void TreeBillboardsApp::BuildDescriptorHeaps()
  621. {
  622.     //
  623.     // Create the SRV heap.
  624.     //
  625.     D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};
  626.     srvHeapDesc.NumDescriptors = 4;
  627.     srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
  628.     srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
  629.     ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&mSrvDescriptorHeap)));
  630.  
  631.     //
  632.     // Fill out the heap with actual descriptors.
  633.     //
  634.     CD3DX12_CPU_DESCRIPTOR_HANDLE hDescriptor(mSrvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
  635.  
  636.     auto grassTex = mTextures["grassTex"]->Resource;
  637.     auto waterTex = mTextures["waterTex"]->Resource;
  638.     auto fenceTex = mTextures["fenceTex"]->Resource;
  639.     auto treeArrayTex = mTextures["treeArrayTex"]->Resource;
  640.  
  641.     D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
  642.     srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
  643.     srvDesc.Format = grassTex->GetDesc().Format;
  644.     srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
  645.     srvDesc.Texture2D.MostDetailedMip = 0;
  646.     srvDesc.Texture2D.MipLevels = -1;
  647.     md3dDevice->CreateShaderResourceView(grassTex.Get(), &srvDesc, hDescriptor);
  648.  
  649.     // next descriptor
  650.     hDescriptor.Offset(1, mCbvSrvDescriptorSize);
  651.  
  652.     srvDesc.Format = waterTex->GetDesc().Format;
  653.     md3dDevice->CreateShaderResourceView(waterTex.Get(), &srvDesc, hDescriptor);
  654.  
  655.     // next descriptor
  656.     hDescriptor.Offset(1, mCbvSrvDescriptorSize);
  657.  
  658.     srvDesc.Format = fenceTex->GetDesc().Format;
  659.     md3dDevice->CreateShaderResourceView(fenceTex.Get(), &srvDesc, hDescriptor);
  660.  
  661.     // next descriptor
  662.     hDescriptor.Offset(1, mCbvSrvDescriptorSize);
  663.  
  664.     auto desc = treeArrayTex->GetDesc();
  665.     srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
  666.     srvDesc.Format = treeArrayTex->GetDesc().Format;
  667.     srvDesc.Texture2DArray.MostDetailedMip = 0;
  668.     srvDesc.Texture2DArray.MipLevels = -1;
  669.     srvDesc.Texture2DArray.FirstArraySlice = 0;
  670.     srvDesc.Texture2DArray.ArraySize = treeArrayTex->GetDesc().DepthOrArraySize;
  671.     md3dDevice->CreateShaderResourceView(treeArrayTex.Get(), &srvDesc, hDescriptor);
  672. }
  673.  
  674. void TreeBillboardsApp::BuildShadersAndInputLayouts()
  675. {
  676.     const D3D_SHADER_MACRO defines[] =
  677.     {
  678.         "FOG", "1",
  679.         NULL, NULL
  680.     };
  681.  
  682.     const D3D_SHADER_MACRO alphaTestDefines[] =
  683.     {
  684.         "FOG", "1",
  685.         "ALPHA_TEST", "1",
  686.         NULL, NULL
  687.     };
  688.  
  689.     mShaders["standardVS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", nullptr, "VS", "vs_5_0");
  690.     mShaders["opaquePS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", defines, "PS", "ps_5_0");
  691.     mShaders["alphaTestedPS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", alphaTestDefines, "PS", "ps_5_0");
  692.     
  693.     mShaders["treeSpriteVS"] = d3dUtil::CompileShader(L"Shaders\\TreeSprite.hlsl", nullptr, "VS", "vs_5_0");
  694.     mShaders["treeSpriteGS"] = d3dUtil::CompileShader(L"Shaders\\TreeSprite.hlsl", nullptr, "GS", "gs_5_0");
  695.     mShaders["treeSpritePS"] = d3dUtil::CompileShader(L"Shaders\\TreeSprite.hlsl", alphaTestDefines, "PS", "ps_5_0");
  696.  
  697.     mStdInputLayout =
  698.     {
  699.         { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  700.         { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  701.         { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  702.     };
  703.  
  704.     mTreeSpriteInputLayout =
  705.     {
  706.         { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  707.         { "SIZE", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  708.     };
  709. }
  710.  
  711. void TreeBillboardsApp::BuildLandGeometry()
  712. {
  713.     GeometryGenerator geoGen;
  714.     GeometryGenerator::MeshData grid = geoGen.CreateGrid(160.0f, 160.0f, 50, 50);
  715.  
  716.     //
  717.     // Extract the vertex elements we are interested and apply the height function to
  718.     // each vertex.  In addition, color the vertices based on their height so we have
  719.     // sandy looking beaches, grassy low hills, and snow mountain peaks.
  720.     //
  721.  
  722.     std::vector<Vertex> vertices(grid.Vertices.size());
  723.     for(size_t i = 0; i < grid.Vertices.size(); ++i)
  724.     {
  725.         auto& p = grid.Vertices[i].Position;
  726.         vertices[i].Pos = p;
  727.         vertices[i].Pos.y = GetHillsHeight(p.x, p.z);
  728.         vertices[i].Normal = GetHillsNormal(p.x, p.z);
  729.         vertices[i].TexC = grid.Vertices[i].TexC;
  730.     }
  731.  
  732.     const UINT vbByteSize = (UINT)vertices.size() * sizeof(Vertex);
  733.  
  734.     std::vector<std::uint16_t> indices = grid.GetIndices16();
  735.     const UINT ibByteSize = (UINT)indices.size() * sizeof(std::uint16_t);
  736.  
  737.     auto geo = std::make_unique<MeshGeometry>();
  738.     geo->Name = "landGeo";
  739.  
  740.     ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
  741.     CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
  742.  
  743.     ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
  744.     CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
  745.  
  746.     geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  747.         mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
  748.  
  749.     geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  750.         mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
  751.  
  752.     geo->VertexByteStride = sizeof(Vertex);
  753.     geo->VertexBufferByteSize = vbByteSize;
  754.     geo->IndexFormat = DXGI_FORMAT_R16_UINT;
  755.     geo->IndexBufferByteSize = ibByteSize;
  756.  
  757.     SubmeshGeometry submesh;
  758.     submesh.IndexCount = (UINT)indices.size();
  759.     submesh.StartIndexLocation = 0;
  760.     submesh.BaseVertexLocation = 0;
  761.  
  762.     geo->DrawArgs["grid"] = submesh;
  763.  
  764.     mGeometries["landGeo"] = std::move(geo);
  765. }
  766.  
  767. void TreeBillboardsApp::BuildWavesGeometry()
  768. {
  769.     std::vector<std::uint16_t> indices(3 * mWaves->TriangleCount()); // 3 indices per face
  770.     assert(mWaves->VertexCount() < 0x0000ffff);
  771.  
  772.     // Iterate over each quad.
  773.     int m = mWaves->RowCount();
  774.     int n = mWaves->ColumnCount();
  775.     int k = 0;
  776.     for(int i = 0; i < m - 1; ++i)
  777.     {
  778.         for(int j = 0; j < n - 1; ++j)
  779.         {
  780.             indices[k] = i*n + j;
  781.             indices[k + 1] = i*n + j + 1;
  782.             indices[k + 2] = (i + 1)*n + j;
  783.  
  784.             indices[k + 3] = (i + 1)*n + j;
  785.             indices[k + 4] = i*n + j + 1;
  786.             indices[k + 5] = (i + 1)*n + j + 1;
  787.  
  788.             k += 6; // next quad
  789.         }
  790.     }
  791.  
  792.     UINT vbByteSize = mWaves->VertexCount()*sizeof(Vertex);
  793.     UINT ibByteSize = (UINT)indices.size()*sizeof(std::uint16_t);
  794.  
  795.     auto geo = std::make_unique<MeshGeometry>();
  796.     geo->Name = "waterGeo";
  797.  
  798.     // Set dynamically.
  799.     geo->VertexBufferCPU = nullptr;
  800.     geo->VertexBufferGPU = nullptr;
  801.  
  802.     ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
  803.     CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
  804.  
  805.     geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  806.         mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
  807.  
  808.     geo->VertexByteStride = sizeof(Vertex);
  809.     geo->VertexBufferByteSize = vbByteSize;
  810.     geo->IndexFormat = DXGI_FORMAT_R16_UINT;
  811.     geo->IndexBufferByteSize = ibByteSize;
  812.  
  813.     SubmeshGeometry submesh;
  814.     submesh.IndexCount = (UINT)indices.size();
  815.     submesh.StartIndexLocation = 0;
  816.     submesh.BaseVertexLocation = 0;
  817.  
  818.     geo->DrawArgs["grid"] = submesh;
  819.  
  820.     mGeometries["waterGeo"] = std::move(geo);
  821. }
  822.  
  823. void TreeBillboardsApp::BuildBoxGeometry()
  824. {
  825.     GeometryGenerator geoGen;
  826.     GeometryGenerator::MeshData box = geoGen.CreateBox(8.0f, 8.0f, 8.0f, 3);
  827.  
  828.     std::vector<Vertex> vertices(box.Vertices.size());
  829.     for (size_t i = 0; i < box.Vertices.size(); ++i)
  830.     {
  831.         auto& p = box.Vertices[i].Position;
  832.         vertices[i].Pos = p;
  833.         vertices[i].Normal = box.Vertices[i].Normal;
  834.         vertices[i].TexC = box.Vertices[i].TexC;
  835.     }
  836.  
  837.     const UINT vbByteSize = (UINT)vertices.size() * sizeof(Vertex);
  838.  
  839.     std::vector<std::uint16_t> indices = box.GetIndices16();
  840.     const UINT ibByteSize = (UINT)indices.size() * sizeof(std::uint16_t);
  841.  
  842.     auto geo = std::make_unique<MeshGeometry>();
  843.     geo->Name = "boxGeo";
  844.  
  845.     ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
  846.     CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
  847.  
  848.     ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
  849.     CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
  850.  
  851.     geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  852.         mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
  853.  
  854.     geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  855.         mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
  856.  
  857.     geo->VertexByteStride = sizeof(Vertex);
  858.     geo->VertexBufferByteSize = vbByteSize;
  859.     geo->IndexFormat = DXGI_FORMAT_R16_UINT;
  860.     geo->IndexBufferByteSize = ibByteSize;
  861.  
  862.     SubmeshGeometry submesh;
  863.     submesh.IndexCount = (UINT)indices.size();
  864.     submesh.StartIndexLocation = 0;
  865.     submesh.BaseVertexLocation = 0;
  866.  
  867.     geo->DrawArgs["box"] = submesh;
  868.  
  869.     mGeometries["boxGeo"] = std::move(geo);
  870. }
  871.  
  872. void TreeBillboardsApp::BuildTreeSpritesGeometry()
  873. {
  874.     struct TreeSpriteVertex
  875.     {
  876.         XMFLOAT3 Pos;
  877.         XMFLOAT2 Size;
  878.     };
  879.  
  880.     static const int treeCount = 16;
  881.     std::array<TreeSpriteVertex, 16> vertices;
  882.     for(UINT i = 0; i < treeCount; ++i)
  883.     {
  884.         float x = MathHelper::RandF(-45.0f, 45.0f);
  885.         float z = MathHelper::RandF(-45.0f, 45.0f);
  886.         float y = GetHillsHeight(x, z);
  887.  
  888.         // Move tree slightly above land height.
  889.         y += 8.0f;
  890.  
  891.         vertices[i].Pos = XMFLOAT3(x, y, z);
  892.         vertices[i].Size = XMFLOAT2(20.0f, 20.0f);
  893.     }
  894.  
  895.     std::array<std::uint16_t, 16> indices =
  896.     {
  897.         0, 1, 2, 3, 4, 5, 6, 7,
  898.         8, 9, 10, 11, 12, 13, 14, 15
  899.     };
  900.  
  901.     const UINT vbByteSize = (UINT)vertices.size() * sizeof(TreeSpriteVertex);
  902.     const UINT ibByteSize = (UINT)indices.size() * sizeof(std::uint16_t);
  903.  
  904.     auto geo = std::make_unique<MeshGeometry>();
  905.     geo->Name = "treeSpritesGeo";
  906.  
  907.     ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
  908.     CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
  909.  
  910.     ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
  911.     CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
  912.  
  913.     geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  914.         mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
  915.  
  916.     geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  917.         mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
  918.  
  919.     geo->VertexByteStride = sizeof(TreeSpriteVertex);
  920.     geo->VertexBufferByteSize = vbByteSize;
  921.     geo->IndexFormat = DXGI_FORMAT_R16_UINT;
  922.     geo->IndexBufferByteSize = ibByteSize;
  923.  
  924.     SubmeshGeometry submesh;
  925.     submesh.IndexCount = (UINT)indices.size();
  926.     submesh.StartIndexLocation = 0;
  927.     submesh.BaseVertexLocation = 0;
  928.  
  929.     geo->DrawArgs["points"] = submesh;
  930.  
  931.     mGeometries["treeSpritesGeo"] = std::move(geo);
  932. }
  933.  
  934. void TreeBillboardsApp::BuildPSOs()
  935. {
  936.     D3D12_GRAPHICS_PIPELINE_STATE_DESC opaquePsoDesc;
  937.  
  938.     //
  939.     // PSO for opaque objects.
  940.     //
  941.     ZeroMemory(&opaquePsoDesc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
  942.     opaquePsoDesc.InputLayout = { mStdInputLayout.data(), (UINT)mStdInputLayout.size() };
  943.     opaquePsoDesc.pRootSignature = mRootSignature.Get();
  944.     opaquePsoDesc.VS = 
  945.     { 
  946.         reinterpret_cast<BYTE*>(mShaders["standardVS"]->GetBufferPointer()), 
  947.         mShaders["standardVS"]->GetBufferSize()
  948.     };
  949.     opaquePsoDesc.PS = 
  950.     { 
  951.         reinterpret_cast<BYTE*>(mShaders["opaquePS"]->GetBufferPointer()),
  952.         mShaders["opaquePS"]->GetBufferSize()
  953.     };
  954.     opaquePsoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
  955.     opaquePsoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
  956.     opaquePsoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
  957.     opaquePsoDesc.SampleMask = UINT_MAX;
  958.     opaquePsoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
  959.     opaquePsoDesc.NumRenderTargets = 1;
  960.     opaquePsoDesc.RTVFormats[0] = mBackBufferFormat;
  961.     opaquePsoDesc.SampleDesc.Count = m4xMsaaState ? 4 : 1;
  962.     opaquePsoDesc.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
  963.     opaquePsoDesc.DSVFormat = mDepthStencilFormat;
  964.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&opaquePsoDesc, IID_PPV_ARGS(&mPSOs["opaque"])));
  965.  
  966.     //
  967.     // PSO for transparent objects
  968.     //
  969.  
  970.     D3D12_GRAPHICS_PIPELINE_STATE_DESC transparentPsoDesc = opaquePsoDesc;
  971.  
  972.     D3D12_RENDER_TARGET_BLEND_DESC transparencyBlendDesc;
  973.     transparencyBlendDesc.BlendEnable = true;
  974.     transparencyBlendDesc.LogicOpEnable = false;
  975.     transparencyBlendDesc.SrcBlend = D3D12_BLEND_SRC_ALPHA;
  976.     transparencyBlendDesc.DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
  977.     transparencyBlendDesc.BlendOp = D3D12_BLEND_OP_ADD;
  978.     transparencyBlendDesc.SrcBlendAlpha = D3D12_BLEND_ONE;
  979.     transparencyBlendDesc.DestBlendAlpha = D3D12_BLEND_ZERO;
  980.     transparencyBlendDesc.BlendOpAlpha = D3D12_BLEND_OP_ADD;
  981.     transparencyBlendDesc.LogicOp = D3D12_LOGIC_OP_NOOP;
  982.     transparencyBlendDesc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
  983.  
  984.     transparentPsoDesc.BlendState.RenderTarget[0] = transparencyBlendDesc;
  985.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&transparentPsoDesc, IID_PPV_ARGS(&mPSOs["transparent"])));
  986.  
  987.     //
  988.     // PSO for alpha tested objects
  989.     //
  990.  
  991.     D3D12_GRAPHICS_PIPELINE_STATE_DESC alphaTestedPsoDesc = opaquePsoDesc;
  992.     alphaTestedPsoDesc.PS = 
  993.     { 
  994.         reinterpret_cast<BYTE*>(mShaders["alphaTestedPS"]->GetBufferPointer()),
  995.         mShaders["alphaTestedPS"]->GetBufferSize()
  996.     };
  997.     alphaTestedPsoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
  998.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&alphaTestedPsoDesc, IID_PPV_ARGS(&mPSOs["alphaTested"])));
  999.  
  1000.     //
  1001.     // PSO for tree sprites
  1002.     //
  1003.     D3D12_GRAPHICS_PIPELINE_STATE_DESC treeSpritePsoDesc = opaquePsoDesc;
  1004.     treeSpritePsoDesc.VS =
  1005.     {
  1006.         reinterpret_cast<BYTE*>(mShaders["treeSpriteVS"]->GetBufferPointer()),
  1007.         mShaders["treeSpriteVS"]->GetBufferSize()
  1008.     };
  1009.     treeSpritePsoDesc.GS =
  1010.     {
  1011.         reinterpret_cast<BYTE*>(mShaders["treeSpriteGS"]->GetBufferPointer()),
  1012.         mShaders["treeSpriteGS"]->GetBufferSize()
  1013.     };
  1014.     treeSpritePsoDesc.PS =
  1015.     {
  1016.         reinterpret_cast<BYTE*>(mShaders["treeSpritePS"]->GetBufferPointer()),
  1017.         mShaders["treeSpritePS"]->GetBufferSize()
  1018.     };
  1019.     treeSpritePsoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
  1020.     treeSpritePsoDesc.InputLayout = { mTreeSpriteInputLayout.data(), (UINT)mTreeSpriteInputLayout.size() };
  1021.     treeSpritePsoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
  1022.  
  1023.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&treeSpritePsoDesc, IID_PPV_ARGS(&mPSOs["treeSprites"])));
  1024. }
  1025.  
  1026. void TreeBillboardsApp::BuildFrameResources()
  1027. {
  1028.     for(int i = 0; i < gNumFrameResources; ++i)
  1029.     {
  1030.         mFrameResources.push_back(std::make_unique<FrameResource>(md3dDevice.Get(),
  1031.             1, (UINT)mAllRitems.size(), (UINT)mMaterials.size(), mWaves->VertexCount()));
  1032.     }
  1033. }
  1034.  
  1035. void TreeBillboardsApp::BuildMaterials()
  1036. {
  1037.     auto grass = std::make_unique<Material>();
  1038.     grass->Name = "grass";
  1039.     grass->MatCBIndex = 0;
  1040.     grass->DiffuseSrvHeapIndex = 0;
  1041.     grass->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
  1042.     grass->FresnelR0 = XMFLOAT3(0.01f, 0.01f, 0.01f);
  1043.     grass->Roughness = 0.125f;
  1044.  
  1045.     // This is not a good water material definition, but we do not have all the rendering
  1046.     // tools we need (transparency, environment reflection), so we fake it for now.
  1047.     auto water = std::make_unique<Material>();
  1048.     water->Name = "water";
  1049.     water->MatCBIndex = 1;
  1050.     water->DiffuseSrvHeapIndex = 1;
  1051.     water->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 0.5f);
  1052.     water->FresnelR0 = XMFLOAT3(0.1f, 0.1f, 0.1f);
  1053.     water->Roughness = 0.0f;
  1054.  
  1055.     auto wirefence = std::make_unique<Material>();
  1056.     wirefence->Name = "wirefence";
  1057.     wirefence->MatCBIndex = 2;
  1058.     wirefence->DiffuseSrvHeapIndex = 2;
  1059.     wirefence->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
  1060.     wirefence->FresnelR0 = XMFLOAT3(0.02f, 0.02f, 0.02f);
  1061.     wirefence->Roughness = 0.25f;
  1062.  
  1063.     auto treeSprites = std::make_unique<Material>();
  1064.     treeSprites->Name = "treeSprites";
  1065.     treeSprites->MatCBIndex = 3;
  1066.     treeSprites->DiffuseSrvHeapIndex = 3;
  1067.     treeSprites->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
  1068.     treeSprites->FresnelR0 = XMFLOAT3(0.01f, 0.01f, 0.01f);
  1069.     treeSprites->Roughness = 0.125f;
  1070.  
  1071.     mMaterials["grass"] = std::move(grass);
  1072.     mMaterials["water"] = std::move(water);
  1073.     mMaterials["wirefence"] = std::move(wirefence);
  1074.     mMaterials["treeSprites"] = std::move(treeSprites);
  1075. }
  1076.  
  1077. void TreeBillboardsApp::BuildRenderItems()
  1078. {
  1079.     auto wavesRitem = std::make_unique<RenderItem>();
  1080.     wavesRitem->World = MathHelper::Identity4x4();
  1081.     XMStoreFloat4x4(&wavesRitem->TexTransform, XMMatrixScaling(5.0f, 5.0f, 1.0f));
  1082.     wavesRitem->ObjCBIndex = 0;
  1083.     wavesRitem->Mat = mMaterials["water"].get();
  1084.     wavesRitem->Geo = mGeometries["waterGeo"].get();
  1085.     wavesRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  1086.     wavesRitem->IndexCount = wavesRitem->Geo->DrawArgs["grid"].IndexCount;
  1087.     wavesRitem->StartIndexLocation = wavesRitem->Geo->DrawArgs["grid"].StartIndexLocation;
  1088.     wavesRitem->BaseVertexLocation = wavesRitem->Geo->DrawArgs["grid"].BaseVertexLocation;
  1089.  
  1090.     mWavesRitem = wavesRitem.get();
  1091.  
  1092.     mRitemLayer[(int)RenderLayer::Transparent].push_back(wavesRitem.get());
  1093.  
  1094.     auto gridRitem = std::make_unique<RenderItem>();
  1095.     gridRitem->World = MathHelper::Identity4x4();
  1096.     XMStoreFloat4x4(&gridRitem->TexTransform, XMMatrixScaling(5.0f, 5.0f, 1.0f));
  1097.     gridRitem->ObjCBIndex = 1;
  1098.     gridRitem->Mat = mMaterials["grass"].get();
  1099.     gridRitem->Geo = mGeometries["landGeo"].get();
  1100.     gridRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  1101.     gridRitem->IndexCount = gridRitem->Geo->DrawArgs["grid"].IndexCount;
  1102.     gridRitem->StartIndexLocation = gridRitem->Geo->DrawArgs["grid"].StartIndexLocation;
  1103.     gridRitem->BaseVertexLocation = gridRitem->Geo->DrawArgs["grid"].BaseVertexLocation;
  1104.  
  1105.     mRitemLayer[(int)RenderLayer::Opaque].push_back(gridRitem.get());
  1106.  
  1107.     auto boxRitem = std::make_unique<RenderItem>();
  1108.     XMStoreFloat4x4(&boxRitem->World, XMMatrixTranslation(3.0f, 2.0f, -9.0f));
  1109.     boxRitem->ObjCBIndex = 2;
  1110.     boxRitem->Mat = mMaterials["wirefence"].get();
  1111.     boxRitem->Geo = mGeometries["boxGeo"].get();
  1112.     boxRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  1113.     boxRitem->IndexCount = boxRitem->Geo->DrawArgs["box"].IndexCount;
  1114.     boxRitem->StartIndexLocation = boxRitem->Geo->DrawArgs["box"].StartIndexLocation;
  1115.     boxRitem->BaseVertexLocation = boxRitem->Geo->DrawArgs["box"].BaseVertexLocation;
  1116.  
  1117.     mRitemLayer[(int)RenderLayer::AlphaTested].push_back(boxRitem.get());
  1118.  
  1119.     auto treeSpritesRitem = std::make_unique<RenderItem>();
  1120.     treeSpritesRitem->World = MathHelper::Identity4x4();
  1121.     treeSpritesRitem->ObjCBIndex = 3;
  1122.     treeSpritesRitem->Mat = mMaterials["treeSprites"].get();
  1123.     treeSpritesRitem->Geo = mGeometries["treeSpritesGeo"].get();
  1124.     treeSpritesRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_POINTLIST;
  1125.     treeSpritesRitem->IndexCount = treeSpritesRitem->Geo->DrawArgs["points"].IndexCount;
  1126.     treeSpritesRitem->StartIndexLocation = treeSpritesRitem->Geo->DrawArgs["points"].StartIndexLocation;
  1127.     treeSpritesRitem->BaseVertexLocation = treeSpritesRitem->Geo->DrawArgs["points"].BaseVertexLocation;
  1128.  
  1129.     mRitemLayer[(int)RenderLayer::AlphaTestedTreeSprites].push_back(treeSpritesRitem.get());
  1130.  
  1131.     mAllRitems.push_back(std::move(wavesRitem));
  1132.     mAllRitems.push_back(std::move(gridRitem));
  1133.     mAllRitems.push_back(std::move(boxRitem));
  1134.     mAllRitems.push_back(std::move(treeSpritesRitem));
  1135. }
  1136.  
  1137. void TreeBillboardsApp::DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems)
  1138. {
  1139.     UINT objCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants));
  1140.     UINT matCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(MaterialConstants));
  1141.  
  1142.     auto objectCB = mCurrFrameResource->ObjectCB->Resource();
  1143.     auto matCB = mCurrFrameResource->MaterialCB->Resource();
  1144.  
  1145.     // For each render item...
  1146.     for(size_t i = 0; i < ritems.size(); ++i)
  1147.     {
  1148.         auto ri = ritems[i];
  1149.  
  1150.         cmdList->IASetVertexBuffers(0, 1, &ri->Geo->VertexBufferView());
  1151.         cmdList->IASetIndexBuffer(&ri->Geo->IndexBufferView());
  1152.         cmdList->IASetPrimitiveTopology(ri->PrimitiveType);
  1153.  
  1154.         CD3DX12_GPU_DESCRIPTOR_HANDLE tex(mSrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart());
  1155.         tex.Offset(ri->Mat->DiffuseSrvHeapIndex, mCbvSrvDescriptorSize);
  1156.  
  1157.         D3D12_GPU_VIRTUAL_ADDRESS objCBAddress = objectCB->GetGPUVirtualAddress() + ri->ObjCBIndex*objCBByteSize;
  1158.         D3D12_GPU_VIRTUAL_ADDRESS matCBAddress = matCB->GetGPUVirtualAddress() + ri->Mat->MatCBIndex*matCBByteSize;
  1159.  
  1160.         cmdList->SetGraphicsRootDescriptorTable(0, tex);
  1161.         cmdList->SetGraphicsRootConstantBufferView(1, objCBAddress);
  1162.         cmdList->SetGraphicsRootConstantBufferView(3, matCBAddress);
  1163.  
  1164.         cmdList->DrawIndexedInstanced(ri->IndexCount, 1, ri->StartIndexLocation, ri->BaseVertexLocation, 0);
  1165.     }
  1166. }
  1167.  
  1168. std::array<const CD3DX12_STATIC_SAMPLER_DESC, 6> TreeBillboardsApp::GetStaticSamplers()
  1169. {
  1170.     // Applications usually only need a handful of samplers.  So just define them all up front
  1171.     // and keep them available as part of the root signature.  
  1172.  
  1173.     const CD3DX12_STATIC_SAMPLER_DESC pointWrap(
  1174.         0, // shaderRegister
  1175.         D3D12_FILTER_MIN_MAG_MIP_POINT, // filter
  1176.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  1177.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  1178.         D3D12_TEXTURE_ADDRESS_MODE_WRAP); // addressW
  1179.  
  1180.     const CD3DX12_STATIC_SAMPLER_DESC pointClamp(
  1181.         1, // shaderRegister
  1182.         D3D12_FILTER_MIN_MAG_MIP_POINT, // filter
  1183.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  1184.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  1185.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP); // addressW
  1186.  
  1187.     const CD3DX12_STATIC_SAMPLER_DESC linearWrap(
  1188.         2, // shaderRegister
  1189.         D3D12_FILTER_MIN_MAG_MIP_LINEAR, // filter
  1190.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  1191.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  1192.         D3D12_TEXTURE_ADDRESS_MODE_WRAP); // addressW
  1193.  
  1194.     const CD3DX12_STATIC_SAMPLER_DESC linearClamp(
  1195.         3, // shaderRegister
  1196.         D3D12_FILTER_MIN_MAG_MIP_LINEAR, // filter
  1197.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  1198.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  1199.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP); // addressW
  1200.  
  1201.     const CD3DX12_STATIC_SAMPLER_DESC anisotropicWrap(
  1202.         4, // shaderRegister
  1203.         D3D12_FILTER_ANISOTROPIC, // filter
  1204.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  1205.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  1206.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressW
  1207.         0.0f,                             // mipLODBias
  1208.         8);                               // maxAnisotropy
  1209.  
  1210.     const CD3DX12_STATIC_SAMPLER_DESC anisotropicClamp(
  1211.         5, // shaderRegister
  1212.         D3D12_FILTER_ANISOTROPIC, // filter
  1213.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  1214.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  1215.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressW
  1216.         0.0f,                              // mipLODBias
  1217.         8);                                // maxAnisotropy
  1218.  
  1219.     return { 
  1220.         pointWrap, pointClamp,
  1221.         linearWrap, linearClamp, 
  1222.         anisotropicWrap, anisotropicClamp };
  1223. }
  1224.  
  1225. float TreeBillboardsApp::GetHillsHeight(float x, float z)const
  1226. {
  1227.     return 0.3f*(z*sinf(0.1f*x) + x*cosf(0.1f*z));
  1228. }
  1229.  
  1230. XMFLOAT3 TreeBillboardsApp::GetHillsNormal(float x, float z)const
  1231. {
  1232.     // n = (-df/dx, 1, -df/dz)
  1233.     XMFLOAT3 n(
  1234.         -0.03f*z*cosf(0.1f*x) - 0.3f*cosf(0.1f*z),
  1235.         1.0f,
  1236.         -0.3f*sinf(0.1f*x) + 0.03f*x*sinf(0.1f*z));
  1237.  
  1238.     XMVECTOR unitNormal = XMVector3Normalize(XMLoadFloat3(&n));
  1239.     XMStoreFloat3(&n, unitNormal);
  1240.  
  1241.     return n;
  1242. }
  1243.